
// Compiler implementation of the D programming language
// Copyright (c) 1999-2008 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.

#ifndef DMD_STATEMENT_H
#define DMD_STATEMENT_H

#ifdef __DMC__
#pragma once
#endif /* __DMC__ */

#include "../l_service/c_ds/root.h"

#include "arraytypes.h"
#include "dsymbol.h"
#include "../l_neo_lexer/lexer.h"

struct OutBuffer;
struct Scope;
struct E_Expression;
struct P_LabelDsymbol;
struct Identifier;
struct S_IfStatement;
struct S_DeclarationStatement;
struct S_DefaultStatement;
struct P_VarDeclaration;
struct Condition;
struct P_Module;
struct Token;
struct InlineCostState;
struct InlineDoState;
struct InlineScanState;
struct S_ReturnStatement;
struct S_CompoundStatement;
struct Argument;
struct P_StaticAssert;
struct S_AsmStatement;
struct S_GotoStatement;
struct S_ScopeStatement;
struct S_TryCatchStatement;
struct S_TryFinallyStatement;
struct HdrGenState;
struct InterState;

LT::T;

// Back end
struct IRState;
struct Blockx;
#if IN_GCC
union tree_node; typedef union tree_node block;
union tree_node; typedef union tree_node elem;
#else
struct block;
struct elem;
#endif
struct code;

/* How a statement exits; this is returned by blockExit()
 */
enum BE
{
    BEnone =	 0,
    BEfallthru = 1,
    BEthrow =    2,
    BEreturn =   4,
    BEgoto =     8,
    BEhalt =	 0x10,
    BEbreak =	 0x20,
    BEcontinue = 0x40,
    BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt),
};

struct S_Statement : Object
{
    Loc loc;

    S_Statement(Loc loc);
    virtual S_Statement *syntaxCopy();

    void oPrint();
    char *oToChars();

    void error(const char *format, ...);
    void warning(const char *format, ...);
    virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    virtual S_TryCatchStatement *isTryCatchStatement() { return NULL; }
    virtual S_GotoStatement *isGotoStatement() { return NULL; }
    virtual S_AsmStatement *isAsmStatement() { return NULL; }
#ifdef _DH
    int incontract;
#endif
    virtual S_ScopeStatement *isScopeStatement() { return NULL; }
    virtual S_Statement *semantic(Scope *sc);
    S_Statement *semanticScope(Scope *sc, S_Statement *sbreak, S_Statement *scontinue);
    virtual int hasBreak();
    virtual int hasContinue();
    virtual int usesEH();
    virtual int blockExit();
    virtual int comeFrom();
    virtual void scopeCode(Scope *sc, S_Statement **sentry, S_Statement **sexit, S_Statement **sfinally);
    virtual Statements *flatten(Scope *sc);
    virtual E_Expression *interpret(InterState *istate);

    virtual int inlineCost(InlineCostState *ics);
    virtual E_Expression *doInline(InlineDoState *ids);
    virtual S_Statement *inlineScan(InlineScanState *iss);

    // Back end
    virtual void toIR(IRState *irs);

    // Avoid dynamic_cast
    virtual S_DeclarationStatement *	isDeclarationStatement(){ return NULL; }
    virtual S_CompoundStatement *		isCompoundStatement()	{ return NULL; }
    virtual S_ReturnStatement *		isReturnStatement()		{ return NULL; }
    virtual S_IfStatement *			isIfStatement()			{ return NULL; }
};

struct S_ExpStatement : S_Statement
{
    E_Expression *exp;

    S_ExpStatement(Loc loc, E_Expression *exp);
    S_Statement *syntaxCopy();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    S_Statement *semantic(Scope *sc);
    E_Expression *interpret(InterState *istate);
    int blockExit();

    int inlineCost(InlineCostState *ics);
    E_Expression *doInline(InlineDoState *ids);
    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_CompileStatement : S_Statement
{
    E_Expression *exp;

    S_CompileStatement(Loc loc, E_Expression *exp);
    S_Statement *syntaxCopy();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    Statements *flatten(Scope *sc);
    S_Statement *semantic(Scope *sc);
};

struct S_DeclarationStatement : S_ExpStatement
{
    // Doing declarations as an expression, rather than a statement,
    // makes inlining functions much easier.

    S_DeclarationStatement(Loc loc, P_Dsymbol *s);
    S_DeclarationStatement(Loc loc, E_Expression *exp);
    S_Statement *syntaxCopy();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    void scopeCode(Scope *sc, S_Statement **sentry, S_Statement **sexit, S_Statement **sfinally);

    S_DeclarationStatement *isDeclarationStatement() { return this; }
};

struct S_CompoundStatement : S_Statement
{
    Statements *statements;

    S_CompoundStatement(Loc loc, Statements *s);
    S_CompoundStatement(Loc loc, S_Statement *s1, S_Statement *s2);
    S_Statement *syntaxCopy();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    S_Statement *semantic(Scope *sc);
    int usesEH();
    int blockExit();
    int comeFrom();
    Statements *flatten(Scope *sc);
    S_ReturnStatement *isReturnStatement();
    E_Expression *interpret(InterState *istate);

    int inlineCost(InlineCostState *ics);
    E_Expression *doInline(InlineDoState *ids);
    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);

    S_CompoundStatement *isCompoundStatement() { return this; }
};

/* The purpose of this is so that continue will go to the next
 * of the statements, and break will go to the end of the statements.
 */
struct S_UnrolledLoopStatement : S_Statement
{
    Statements *statements;

    S_UnrolledLoopStatement(Loc loc, Statements *statements);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    int inlineCost(InlineCostState *ics);
    E_Expression *doInline(InlineDoState *ids);
    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_ScopeStatement : S_Statement
{
    S_Statement *statement;

    S_ScopeStatement(Loc loc, S_Statement *s);
    S_Statement *syntaxCopy();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    S_ScopeStatement *isScopeStatement() { return this; }
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_WhileStatement : S_Statement
{
    E_Expression *condition;
    S_Statement *body;

    S_WhileStatement(Loc loc, E_Expression *c, S_Statement *b);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_DoStatement : S_Statement
{
    S_Statement *body;
    E_Expression *condition;

    S_DoStatement(Loc loc, S_Statement *b, E_Expression *c);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_ForStatement : S_Statement
{
    S_Statement *init;
    E_Expression *condition;
    E_Expression *increment;
    S_Statement *body;

    S_ForStatement(Loc loc, S_Statement *init, E_Expression *condition, E_Expression *increment, S_Statement *body);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    void scopeCode(Scope *sc, S_Statement **sentry, S_Statement **sexit, S_Statement **sfinally);
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_ForeachStatement : S_Statement
{
    LT::T op;		// LT::TOKforeach or LT::TOKforeach_reverse
    Arguments *arguments;	// array of Argument*'s
    E_Expression *aggr;
    S_Statement *body;

    P_VarDeclaration *key;
    P_VarDeclaration *value;

    P_FuncDeclaration *func;	// function we're lexically in

    Array cases;	// put breaks, continues, gotos and returns here
    Array gotos;	// forward referenced goto's go here

    S_ForeachStatement(Loc loc, LT::T op, Arguments *arguments, E_Expression *aggr, S_Statement *body);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    bool checkForArgTypes();
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_ForeachRangeStatement : S_Statement
{
    LT::T op;		// LT::TOKforeach or LT::TOKforeach_reverse
    Argument *arg;		// loop index variable
    E_Expression *lwr;
    E_Expression *upr;
    S_Statement *body;

    P_VarDeclaration *key;

    S_ForeachRangeStatement(Loc loc, LT::T op, Argument *arg,
	E_Expression *lwr, E_Expression *upr, S_Statement *body);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_IfStatement : S_Statement
{
    Argument *arg;
    E_Expression *condition;
    S_Statement *ifbody;
    S_Statement *elsebody;

    P_VarDeclaration *match;	// for MatchExpression results

    S_IfStatement(Loc loc, Argument *arg, E_Expression *condition, S_Statement *ifbody, S_Statement *elsebody);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    int usesEH();
    int blockExit();
    S_IfStatement *isIfStatement() { return this; }

    int inlineCost(InlineCostState *ics);
    E_Expression *doInline(InlineDoState *ids);
    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_ConditionalStatement : S_Statement
{
    Condition *condition;
    S_Statement *ifbody;
    S_Statement *elsebody;

    S_ConditionalStatement(Loc loc, Condition *condition, S_Statement *ifbody, S_Statement *elsebody);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    Statements *flatten(Scope *sc);
    int usesEH();
    int blockExit();

    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
};

struct S_PragmaStatement : S_Statement
{
    Identifier *ident;
    Expressions *args;		// array of E_Expression's
    S_Statement *body;

    S_PragmaStatement(Loc loc, Identifier *ident, Expressions *args, S_Statement *body);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int usesEH();
    int blockExit();

    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    void toIR(IRState *irs);
};

struct S_StaticAssertStatement : S_Statement
{
    P_StaticAssert *sa;

    S_StaticAssertStatement(P_StaticAssert *sa);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);

    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
};

struct S_SwitchStatement : S_Statement
{
    E_Expression *condition;
    S_Statement *body;

    S_DefaultStatement *sdefault;
    S_TryFinallyStatement *tf;
    Array gotoCases;		// array of unresolved S_GotoCaseStatement's
    Array *cases;		// array of S_CaseStatement's
    int hasNoDefault;		// !=0 if no default statement
    int hasVars;		// !=0 if has variable case values

    S_SwitchStatement(Loc loc, E_Expression *c, S_Statement *b);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int usesEH();
    int blockExit();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_CaseStatement : S_Statement
{
    E_Expression *exp;
    S_Statement *statement;
    int index;		// which case it is (since we sort this)
    block *cblock;	// back end: label for the block

    S_CaseStatement(Loc loc, E_Expression *exp, S_Statement *s);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int oCompare(Object *obj);
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_DefaultStatement : S_Statement
{
    S_Statement *statement;
#if IN_GCC
    block *cblock;	// back end: label for the block
#endif

    S_DefaultStatement(Loc loc, S_Statement *s);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_GotoDefaultStatement : S_Statement
{
    S_SwitchStatement *sw;

    S_GotoDefaultStatement(Loc loc);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    E_Expression *interpret(InterState *istate);
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    void toIR(IRState *irs);
};

struct S_GotoCaseStatement : S_Statement
{
    E_Expression *exp;		// NULL, or which case to goto
    S_CaseStatement *cs;		// case statement it resolves to

    S_GotoCaseStatement(Loc loc, E_Expression *exp);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    E_Expression *interpret(InterState *istate);
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    void toIR(IRState *irs);
};

struct S_SwitchErrorStatement : S_Statement
{
    S_SwitchErrorStatement(Loc loc);
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    void toIR(IRState *irs);
};

struct S_ReturnStatement : S_Statement
{
    E_Expression *exp;

    S_ReturnStatement(Loc loc, E_Expression *exp);
    S_Statement *syntaxCopy();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    S_Statement *semantic(Scope *sc);
    int blockExit();
    E_Expression *interpret(InterState *istate);

    int inlineCost(InlineCostState *ics);
    E_Expression *doInline(InlineDoState *ids);
    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);

    S_ReturnStatement *isReturnStatement() { return this; }
};

struct S_BreakStatement : S_Statement
{
    Identifier *ident;

    S_BreakStatement(Loc loc, Identifier *ident);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    E_Expression *interpret(InterState *istate);
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    void toIR(IRState *irs);
};

struct S_ContinueStatement : S_Statement
{
    Identifier *ident;

    S_ContinueStatement(Loc loc, Identifier *ident);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    E_Expression *interpret(InterState *istate);
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    void toIR(IRState *irs);
};

struct S_SynchronizedStatement : S_Statement
{
    E_Expression *exp;
    S_Statement *body;

    S_SynchronizedStatement(Loc loc, E_Expression *exp, S_Statement *body);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

// Back end
    elem *esync;
    S_SynchronizedStatement(Loc loc, elem *esync, S_Statement *body);
    void toIR(IRState *irs);
};

struct S_WithStatement : S_Statement
{
    E_Expression *exp;
    S_Statement *body;
    P_VarDeclaration *wthis;

    S_WithStatement(Loc loc, E_Expression *exp, S_Statement *body);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    int usesEH();
    int blockExit();

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_TryCatchStatement : S_Statement
{
    S_Statement *body;
    Array *catches;

    S_TryCatchStatement(Loc loc, S_Statement *body, Array *catches);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int usesEH();
    int blockExit();

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    S_TryCatchStatement *isTryCatchStatement() { return this; }
};

struct Catch : Object
{
    Loc loc;
    Type *type;
    Identifier *ident;
    P_VarDeclaration *var;
    S_Statement *handler;

    Catch(Loc loc, Type *t, Identifier *id, S_Statement *handler);
    Catch *syntaxCopy();
    void semantic(Scope *sc);
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
};

struct S_TryFinallyStatement : S_Statement
{
    S_Statement *body;
    S_Statement *finalbody;

    S_TryFinallyStatement(Loc loc, S_Statement *body, S_Statement *finalbody);
    S_Statement *syntaxCopy();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    S_Statement *semantic(Scope *sc);
    int hasBreak();
    int hasContinue();
    int usesEH();
    int blockExit();

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_OnScopeStatement : S_Statement
{
    LT::T tok;
    S_Statement *statement;

    S_OnScopeStatement(Loc loc, LT::T tok, S_Statement *statement);
    S_Statement *syntaxCopy();
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    S_Statement *semantic(Scope *sc);
    int usesEH();
    void scopeCode(Scope *sc, S_Statement **sentry, S_Statement **sexit, S_Statement **sfinally);

    void toIR(IRState *irs);
};

struct S_ThrowStatement : S_Statement
{
    E_Expression *exp;

    S_ThrowStatement(Loc loc, E_Expression *exp);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    int blockExit();

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_VolatileStatement : S_Statement
{
    S_Statement *statement;

    S_VolatileStatement(Loc loc, S_Statement *statement);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    Statements *flatten(Scope *sc);
    int blockExit();
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct S_GotoStatement : S_Statement
{
    Identifier *ident;
    P_LabelDsymbol *label;
    S_TryFinallyStatement *tf;

    S_GotoStatement(Loc loc, Identifier *ident);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int blockExit();
    E_Expression *interpret(InterState *istate);

    void toIR(IRState *irs);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    S_GotoStatement *isGotoStatement() { return this; }
};

struct S_LabelStatement : S_Statement
{
    Identifier *ident;
    S_Statement *statement;
    S_TryFinallyStatement *tf;
    block *lblock;		// back end
    int isReturnLabel;

    S_LabelStatement(Loc loc, Identifier *ident, S_Statement *statement);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    Statements *flatten(Scope *sc);
    int usesEH();
    int blockExit();
    int comeFrom();
    E_Expression *interpret(InterState *istate);
    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);

    S_Statement *inlineScan(InlineScanState *iss);

    void toIR(IRState *irs);
};

struct P_LabelDsymbol : P_Dsymbol
{
    S_LabelStatement *statement;
#if IN_GCC
    unsigned asmLabelNum;       // GCC-specific
#endif

    P_LabelDsymbol(Identifier *ident);
    P_LabelDsymbol *isLabel();
};

struct S_AsmStatement : S_Statement
{
    Token *tokens;
    code *asmcode;
    unsigned asmalign;		// alignment of this statement
    unsigned refparam;		// !=0 if function parameter is referenced
    unsigned naked;		// !=0 if function is to be naked
    unsigned regs;		// mask of registers modified

    S_AsmStatement(Loc loc, Token *tokens);
    S_Statement *syntaxCopy();
    S_Statement *semantic(Scope *sc);
    int blockExit();
    int comeFrom();

    void toCBuffer(OutBuffer *buf, HdrGenState *hgs);
    virtual S_AsmStatement *isAsmStatement() { return this; }

    void toIR(IRState *irs);
};

#endif /* DMD_STATEMENT_H */
